package com.sky.orders.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.sky.constant.MessageConstant;
import com.sky.dto.*;
import com.sky.entity.OrderDetail;
import com.sky.entity.Orders;
import com.sky.exception.OrderBusinessException;
import com.sky.orderdetail.service.OrderDetailService;
import com.sky.orders.mapper.OrderMapper;
import com.sky.orders.service.OrderService;
import com.sky.result.PageResult;
import com.sky.utils.WeChatPayUtil;
import com.sky.vo.OrderStatisticsVO;
import com.sky.vo.OrderVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 订单管理 serviceImpl
 */
@Slf4j
@Service
public class OrderServiceImpl implements OrderService {


    @Resource
    private OrderMapper orderMapper;

    @Resource
    private OrderDetailService orderDetailService;

    @Resource
    private WeChatPayUtil weChatPayUtil;




    /**
     * 订单管理
     *        分页-条件查询
     * @param ordersPageQueryDTO
     */
    @Override
    public PageResult queryPage(OrdersPageQueryDTO ordersPageQueryDTO) {
        // 1.PageHelper设置分页参数 设置排序字段
        PageHelper.startPage(ordersPageQueryDTO.getPage(), ordersPageQueryDTO.getPageSize(), "order_time desc");

        // 2.查询返回的订单集合 封装为PageHelper的集合
        Page<Orders> page = orderMapper.selectPage(ordersPageQueryDTO);

        // 3.创建List<OrderVO>集合 收集数据，如果没有，则为[],也可以返回给前端 防止最后return报错
        List<OrderVO> orderVOList = new ArrayList<>();

        // 4.非空校验
        if(Objects.nonNull(page) && page.getTotal() > 0){
            orderVOList = page.getResult().stream().map(orders -> {
                // 对象拷贝
                OrderVO orderVO = JSON.parseObject(JSON.toJSONString(orders, SerializerFeature.WriteMapNullValue), OrderVO.class);
                // 根据orderId，查询订单对应的明细集合
                List<OrderDetail> orderDetailList = orderDetailService.selectOrderDetailListByOrderId(orders.getId());
                // 判断 封装数据
                if (!CollectionUtils.isEmpty(orderDetailList)) {
                    // 订单明细集合
                    orderVO.setOrderDetailList(orderDetailList);
                    // 订单中，菜品名称和数量信息   可乐*3;啤酒*2;......
                    String orderDishes = orderDetailList.stream().map(orderDetail -> orderDetail.getName() + "*" + orderDetail.getNumber()).collect(Collectors.joining(";"));
                    orderVO.setOrderDishes(orderDishes);
                }
                return orderVO;
            }).collect(Collectors.toList());
        }
        return new PageResult(page.getTotal(), orderVOList);
    }



    /**
     * 订单管理
     *        根据订单id，查询订单和明细列表
     * @param id
     */
    @Override
    public OrderVO getOrderAndOrderDetailById(Long id) {
        // 1.查订单
        Orders orders = orderMapper.getById(id);

        // 2.查询订单明细
        List<OrderDetail> orderDetailList = orderDetailService.selectOrderDetailListByOrderId(orders.getId());

        // 3.对象拷贝，封装数据返回
        OrderVO orderVO = JSON.parseObject(JSON.toJSONString(orders, SerializerFeature.WriteMapNullValue), OrderVO.class);
        if( !CollectionUtils.isEmpty(orderDetailList) ){
            // 订单明细
            orderVO.setOrderDetailList(orderDetailList);
            // 订单中，菜品名称和数量信息   可乐*3;啤酒*2;......
            String orderDishes = orderDetailList.stream().map(orderDetail -> orderDetail.getName() + "*" + orderDetail.getNumber()).collect(Collectors.joining(";"));
            orderVO.setOrderDishes(orderDishes);
        }
        return orderVO;
    }



    /**
     * 订单管理
     *        统计订单订单状态为 status= 2待接单 3已接单 4派送中 5已完成 6已取消 数量
     */
    @Override
    public OrderStatisticsVO statusCounts() {
        // 2待接单
        Integer tobeConfirmedCounts = orderMapper.statusCounts(Orders.TO_BE_CONFIRMED);
        tobeConfirmedCounts = tobeConfirmedCounts == null ? 0 : tobeConfirmedCounts;
        // 3已接单
        Integer confirmedCounts = orderMapper.statusCounts(Orders.CONFIRMED);
        confirmedCounts = confirmedCounts == null ? 0 : confirmedCounts;
        // 4派送中
        Integer deliveryInProgressCounts = orderMapper.statusCounts(Orders.DELIVERY_IN_PROGRESS);
        deliveryInProgressCounts = deliveryInProgressCounts == null ? 0 : deliveryInProgressCounts;
        // 5已完成
        Integer completedCounts = orderMapper.statusCounts(Orders.COMPLETED);
        completedCounts = completedCounts == null ? 0 : completedCounts;
        // 6已取消
        Integer cancelledCounts = orderMapper.statusCounts(Orders.CANCELLED);
        cancelledCounts = cancelledCounts == null ? 0 : cancelledCounts;

        // 封装返回
        return OrderStatisticsVO.builder()
                .toBeConfirmed(tobeConfirmedCounts)
                .confirmed(confirmedCounts)
                .deliveryInProgress(deliveryInProgressCounts)
                .completed(completedCounts)
                .cancelled(cancelledCounts)
                .build();
    }



    /**
     * 订单管理
     *        接单(修改订单状态)
     * @param ordersConfirmDTO
     */
    @Override
    public void receiveOrders(OrdersConfirmDTO ordersConfirmDTO) {
        Integer status = ordersConfirmDTO.getStatus();
        if(Objects.isNull(status)){
            status = Orders.CONFIRMED;          //环环相扣
        }
        Orders orders = Orders.builder().id(ordersConfirmDTO.getId()).status(status).build();
        Integer count = orderMapper.updateById(orders);
        log.info("订单id: {},已接单，影响数据行数: {}", ordersConfirmDTO.getId(), count);
    }



    /**
     * 订单管理
     *        拒单
     * - 商家拒单其实就是将订单状态修改为“已取消”
     * - 只有订单处于“待接单”状态时可以执行拒单操作
     * - 商家拒单时需要指定拒单原因
     * - 商家拒单时，如果用户已经完成了支付，需要为用户退款
     * @param ordersRejectionDTO
     */
    @Override
    public void rejectionOrders(OrdersRejectionDTO ordersRejectionDTO) {
        // 1.查询订单
        Orders orders = orderMapper.getById(ordersRejectionDTO.getId());
        // 2.校验
        if(Objects.isNull(orders)){
            throw new OrderBusinessException(MessageConstant.ORDER_NOT_FOUND);
        }
        // 3.判断订单状态,待接单状态 才能拒单         1待付款 2待接单 3已接单 4派送中 5已完成 6已取消   //环环相扣
        if( !Objects.equals(orders.getStatus(), Orders.TO_BE_CONFIRMED) ){
            throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
        }

        //创建修改订单对象
        Orders updateOrder = new Orders();
        updateOrder.setId(orders.getId());

        // 4.判断支付状态，已支付则需要退款   支付状态:0未支付 1已支付 2退款        商家退款使用的支付状态
        if(orders.getPayStatus() == Orders.PAID){
            // 用户已经支付，需退款
            try {
                String refund = weChatPayUtil.refund(
                        orders.getNumber(), //商户订单号
                        orders.getNumber(), //商户退款单号
                        orders.getAmount(), //退款金额，单位 元
                        orders.getAmount()  //原订单金额
                );
                log.info("订单id: {},订单号: {},商户拒单，退款结果: {}", orders.getId(), orders.getNumber(), refund);

                //设置 支付状态payStatus=2退款
                updateOrder.setPayStatus(Orders.REFUND);
            } catch (Exception e) {
                log.info("订单号: {},订单金额:{},商户拒单,调用WeChatPay微信服务--退款失败", orders.getNumber(), orders.getAmount());
                throw new OrderBusinessException(MessageConstant.ORDER_REFUND_ERROR);
            }
        }
        //拒单需要退款，根据订单id更新订单状态、拒单原因、取消时间
        updateOrder.setStatus(Orders.CANCELLED);  //订单状态status=6 取消
        updateOrder.setRejectionReason(ordersRejectionDTO.getRejectionReason());
        updateOrder.setCancelTime(LocalDateTime.now());
        // 5.修改订单信息
        Integer count = orderMapper.updateById(updateOrder);
        log.info("订单id: {},商户拒单操作成功,影响行数: {}", orders.getId(), count);
    }



    /**
     * 订单管理
     *        商家取消订单
     * - 取消订单其实就是将订单状态修改为“已取消”
     * - 商家取消订单时需要指定取消原因
     * - 商家取消订单时，如果用户已经完成了支付，需要为用户退款
     * @param ordersCancelDTO
     */
    @Override
    public void merchantCancelOrder(OrdersCancelDTO ordersCancelDTO) {
        // 1.查询订单
        Orders orders = orderMapper.getById(ordersCancelDTO.getId());
        // 2.非空校验
        if(Objects.isNull(orders)){
            throw new OrderBusinessException(MessageConstant.ORDER_NOT_FOUND);
        }

        // 创建修改订单的对象
        Orders updateOrder = new Orders();
        updateOrder.setId(orders.getId());

        // 3.判断订单支付状态payStatus是否已支付
        if(orders.getPayStatus() == Orders.PAID){
            // 用户已经支付，需退款
            try {
                String refund = weChatPayUtil.refund(
                        orders.getNumber(), //商户订单号
                        orders.getNumber(), //商户退款单号
                        orders.getAmount(), //退款金额，单位 元
                        orders.getAmount()  //原订单金额
                );
                log.info("订单id: {},订单号: {},商家取消订单,WeChatPay退款结果: {}", orders.getId(), orders.getNumber(), refund);

                //修改为支付状态 退款 payStatus=2
                updateOrder.setPayStatus(Orders.REFUND);
            } catch (Exception e) {
                log.info("订单号: {},订单金额:{},商户取消订单,调用WeChatPay微信服务--退款失败", orders.getNumber(), orders.getAmount());
                throw new OrderBusinessException(MessageConstant.ORDER_REFUND_ERROR);
            }
        }
        // 设置商家取消订单的状态、原因、时间
        updateOrder.setStatus(Orders.CANCELLED);
        updateOrder.setCancelReason(ordersCancelDTO.getCancelReason());
        updateOrder.setCancelTime(LocalDateTime.now());
        // 4.修改订单信息
        Integer count = orderMapper.updateById(updateOrder);
        log.info("订单id: {},商户取消订单成功,影响行数: {}", orders.getId(), count);
    }



    /**
     * 订单管理
     *        派送
     * @param id
     */
    @Override
    public void deliveryOrder(Long id) {
        // 1.根据id查询订单
        Orders orders = orderMapper.getById(id);
        // 2.非空判断
        if(Objects.isNull(orders)){
            throw new OrderBusinessException(MessageConstant.ORDER_NOT_FOUND);
        }
        // 3.状态校验  //环环相扣
        if( !Objects.equals(orders.getStatus(), Orders.CONFIRMED) ){
            throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
        }

        // 4.封装修改数据
        Orders updateOrders = Orders.builder().id(id).status(Orders.DELIVERY_IN_PROGRESS).build();
        // 5.修改数订单信息
        Integer count = orderMapper.updateById(updateOrders);
        log.info("订单id: {},改为派送,影响行数: {}", orders.getId(), count);
    }



    /**
     * 订单管理
     *        完成送达
     * @param id
     */
    @Override
    public void completeOrder(Long id) {
        // 1.根据id查订单
        Orders orders = orderMapper.getById(id);
        // 2.非空判断
        if(Objects.isNull(orders)){
            throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
        }
        // 3.状态校验  //环环相扣
        if( !Objects.equals(orders.getStatus(), Orders.DELIVERY_IN_PROGRESS)){
            throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
        }

        // 4.封装修改
        Orders uodateOrder = Orders.builder().id(id).status(Orders.COMPLETED).deliveryTime(LocalDateTime.now()).build();
        // 5.修改订单数据
        Integer count = orderMapper.updateById(uodateOrder);
        log.info("订单id: {},已完成送达,影响行数: {}", id, count);
    }



    /**
     * 定时任务
     *        查询订单状态status=1待支付、payStatus=0未支付、下单时间+15min < 当前时间 的订单集合
     * @param status
     * @param payStatus
     * @param orderTimeout
     */
    @Override
    public List<Orders> getTimeOutOrders(Integer status, Integer payStatus, Long orderTimeout) {
        return orderMapper.getTimeOutOrders(status, payStatus, orderTimeout);
    }



    /**
     * 定时任务
     *        根据id修改订单
     * @param updateOrder
     */
    @Override
    public void updateById(Orders updateOrder) {
        orderMapper.updateById(updateOrder);
    }



    /**
     * 订单管理
     *       根据状态status=4派送中，以及下单时间+2h < 当前时间 查询订单集合
     * @param status
     * @param deliveryTime
     */
    @Override
    public List<Orders> getDeliveryOrders(Integer status, Integer deliveryTime) {
        return orderMapper.getDeliveryOrders(status, deliveryTime);
    }



    /**
     * 订单管理
     *        查询当天营业总额 (状态已完成)
     * @param map
     */
    @Override
    public BigDecimal selectDayTotalAmountByMap(Map map) {
        return orderMapper.selectDayTotalAmountByMap(map);
    }



    /**
     * 订单管理
     *        数据统计
     * @param map
     */
    @Override
    public Integer getOrderStatisticsByMap(Map map) {
        return orderMapper.selectOrderStatisticsByMap(map);
    }



    /**
     * 订单管理
     *        热销商品统计
     * @param map
     */
    @Override
    public List<GoodsSalesDTO> selectSalesTop10Statistics(Map map) {
        return orderMapper.selectSalesTop10Statistics(map);
    }
}
